﻿using ShiQuan.RemoteHelper;
using ShiQuan.Remoting.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace ShiQuan.RemoteServer
{
    /// <summary>
    /// 服务器
    /// </summary>
    public class SocketServer : IDisposable
    {
        private Socket _socket = null;
        private TcpListener tcpListener = null;
        private int _port = 18888;
        private Dictionary<string, IBaseAction> dicAction = null;
        private void InitAction()
        {
            this.dicAction = new Dictionary<string, IBaseAction>();
            //this.dicAction.Add("Regist", new RegistAction());
            //this.dicAction.Add("GetRemoteInfo", new GetRemoteInfoAction());
            this.dicAction.Add("SendFile", new SendFileAction());
        }
        /// <summary>
        /// 获取服务器端口
        /// </summary>
        public int Port
        {
            get { return this._port; }
        }
        /// <summary>
        /// 启动本地
        /// </summary>
        public bool Start(out string msg)
        {
            msg = string.Empty;
            try
            {
                /*初始方法*/
                this.InitAction();

                _port = 18888;
                if (string.IsNullOrEmpty(AppConfig.LocalPort) == false)
                    int.TryParse(AppConfig.LocalPort, out _port);

                //_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);  //侦听socket
                //_socket.Bind(new IPEndPoint(IPAddress.Any, _port));
                //_socket.Listen(100);
                //_socket.BeginAccept(new AsyncCallback(OnAccept), _socket);  //开始接收来自浏览器的http请求（其实是socket连接请求）
                //Logger.Info("服务器启动成功！");

                // 获得本机的Ip地址，即127.0.0.1
                IPAddress localaddress = IPAddress.Loopback;
                // 创建可以访问的断点，49155表示端口号，如果这里设置为0，表示使用一个由系统分配的空闲的端口号
                IPEndPoint endpoint = new IPEndPoint(localaddress, _port);
                this.tcpListener = new TcpListener(endpoint);
                // 启动监听
                this.tcpListener.Start();
                this.tcpListener.BeginAcceptTcpClient(new AsyncCallback(OnTcpAccept), this.tcpListener);
                Logger.Info("服务器启动成功！");
                msg = "服务器启动成功";
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error("服务器启动异常", ex);
                msg = "服务器启动异常";
                return false;
            }

        }
        void OnTcpAccept(IAsyncResult ar)
        {
            TcpClient mClient = null;
            try
            {
                TcpListener listener = ar.AsyncState as TcpListener;
                mClient = listener.EndAcceptTcpClient(ar);  //接收到来自浏览器的代理socket
                //NO.1  开始下一次请求接收（此行代码放在NO.2处时，就是串行处理http请求，前一次处理过程会阻塞下一次请求处理）
                listener.BeginAcceptTcpClient(new AsyncCallback(OnTcpAccept), listener);
            }
            catch (Exception ex)
            {
                Logger.Error("接收请求异常", ex);
            }
            if (mClient == null)
                return;

            RequestHeader header = null;
            try
            {
                header = this.ReadHeader(mClient);
                if (header == null || string.IsNullOrEmpty(header.Action)
                   || this.dicAction.ContainsKey(header.Action) == false)
                {
                    this.Fail(mClient.Client, "未能找到处理方法");
                    return;
                }
                if (header.ContentLength <= 0)
                {
                    this.Fail(mClient.Client, "内容不能为空！");
                    return;
                }
                this.dicAction[header.Action].Business(this, mClient.Client, header);
            }
            catch (Exception ex)
            {
                Logger.Error("解释处理异常", ex);
                this.Fail(mClient.Client, "解释处理异常");
                return;
            }
        }
        /// <summary>
        /// 读取请求头
        /// </summary>
        /// <param name="mClient"></param>
        /// <returns></returns>
        public RequestHeader ReadHeader(TcpClient mClient)
        {
            RequestHeader header = new RequestHeader();
            StringBuilder content = new StringBuilder();
            string line;
            NetworkStream stream = mClient.GetStream();
            while ((line = ReadLine(stream)) != null)
            {
                content.AppendLine(line);
                if (line.Equals(""))
                {
                    Logger.Info("request", mClient.Client.RemoteEndPoint.ToString() + " 请求头：\n" + content.ToString());
                    return header;
                }
                int separator = line.IndexOf(':');
                if (separator == -1)
                {
                    throw new Exception("invalid http header line: " + line);
                }
                String name = line.Substring(0, separator);
                int pos = separator + 1;
                while ((pos < line.Length) && (line[pos] == ' '))
                {
                    pos++; // strip any spaces
                }
                string value = line.Substring(pos, line.Length - pos);
                Console.WriteLine("header: {0}:{1}", name, value);
                header.Set(name, value);
            }
            return header;
        }
        private string ReadLine(NetworkStream stream)
        {
            int next = -1;
            List<byte> list = new List<byte>();
            while (true)
            {
                next = stream.ReadByte();
                if (next == '\n') { break; }
                if (next == '\r') { continue; }
                if (next == -1)
                {
                    //Thread.Sleep(1); 
                    continue;
                };
                //data += Convert.ToChar(next);
                list.Add(Convert.ToByte(next));
            }
            //return data;
            return System.Text.Encoding.UTF8.GetString(list.ToArray());
        }
        void OnAccept(IAsyncResult ar)
        {
            Socket mClient = null;
            try
            {
                Socket socket = ar.AsyncState as Socket;
                mClient = socket.EndAccept(ar);  //接收到来自浏览器的代理socket
                //NO.1  开始下一次请求接收（此行代码放在NO.2处时，就是串行处理http请求，前一次处理过程会阻塞下一次请求处理）
                socket.BeginAccept(new AsyncCallback(OnAccept), socket);
            }
            catch (Exception ex)
            {
                Logger.Error("接收请求异常", ex);
            }
            try
            {
                if (mClient == null)
                    return;

                byte[] mBuffer = new byte[1024 * 1024];
                int real_recv = mClient.Receive(mBuffer);  //接收浏览器的请求数据
                string recv_request = Encoding.UTF8.GetString(mBuffer, 0, real_recv);
                Logger.Info("request", mClient.RemoteEndPoint.ToString() + " 请求信息：\n" + recv_request);  //将请求显示到界面
                //Resolve(recv_request, mClient);  //解析、路由、处理
                this.Response(mClient, "{code:\"0\",msg:\"ok\"}");
            }
            catch (Exception ex)
            {
                Logger.Error("解释处理异常", ex);
                this.Response(mClient, "{code:\"99\",msg:\"解释处理异常\"}");
            }
        }
        /// <summary>
        /// 按照HTTP协议格式 解析浏览器发送的请求字符串
        /// </summary>
        /// <param name="request"></param>
        /// <param name="client"></param>
        void Resolve(string request, Socket client)
        {
            //浏览器发送的请求字符串request格式类似这样：
            //GET /index.html HTTP/1.1
            //Host: 127.0.0.1:8081
            //Connection: keep-alive
            //Cache-Control: max-age=0
            //
            //id=123&pass=123       （post方式提交的表单数据，get方式提交数据直接在url中）

            string[] strs = request.Split(new string[] { "\r\n" }, StringSplitOptions.None);  //以“换行”作为切分标志
            if (strs.Length > 0)  //解析出请求路径、post传递的参数(get方式传递参数直接从url中解析)
            {
                string[] items = strs[0].Split(' ');  //items[1]表示请求url中的路径部分（不含主机部分）
                Dictionary<string, string> param = new Dictionary<string, string>();

                if (strs.Contains(""))  //包含空行  说明存在post数据
                {
                    string post_data = strs[strs.Length - 1]; //最后一项
                    if (post_data != "")
                    {
                        string[] post_datas = post_data.Split('&');
                        foreach (string s in post_datas)
                        {
                            param.Add(s.Split('=')[0], s.Split('=')[1]);
                        }
                    }
                }
                Route(items[1], param, client);  //路由处理
            }
        }

        /// <summary>
        /// 按照请求路径（不包括主机部分）  进行路由处理
        /// </summary>
        /// <param name="path"></param>
        /// <param name="param"></param>
        /// <param name="client"></param>
        void Route(string path, Dictionary<string, string> param, Socket client)
        {
            if (path.EndsWith("index.html") || path.EndsWith("/"))  //请求首页
            {
                //Home.HomePage(response);
                string statusline = "HTTP/1.1 200 OK\r\n";   //状态行
                byte[] statusline_to_bytes = Encoding.UTF8.GetBytes(statusline);

                string content =
                "<html>" +
                    "<head>" +
                        "<title>socket webServer  -- Login</title>" +
                    "</head>" +
                    "<body>" +
                       "<div style=\"text-align:center\">" +
                           "<form method=\"post\" action=\"/login.zsp\">" +
                               "用户名:&nbsp;<input name=\"id\" /><br />" +
                               "密码:&nbsp;&nbsp;&nbsp;<input name=\"pass\" type=\"password\"/><br />" +
                               "<input  type=\"submit\" value=\"登录\"/>" +
                           "</form>" +
                       "</div>" +
                    "</body>" +
                "</html>";  //内容

                byte[] content_to_bytes = Encoding.UTF8.GetBytes(content);

                string header = string.Format("Content-Type:text/html;charset=UTF-8\r\nContent-Length:{0}\r\n", content_to_bytes.Length);
                byte[] header_to_bytes = Encoding.UTF8.GetBytes(header);  //应答头

                client.Send(statusline_to_bytes);  //发送状态行
                client.Send(header_to_bytes);  //发送应答头
                client.Send(new byte[] { (byte)'\r', (byte)'\n' });  //发送空行
                client.Send(content_to_bytes);  //发送正文（html）

                client.Close();
            }
            else if (path.EndsWith("login.zsp"))  //登录 处理页面
            {
                //User.LoginCheck(param["id"], param["pass"], response);
            }
            //...
        }
        #region 响应
        /// <summary>
        /// 失败
        /// </summary>
        /// <param name="client"></param>
        /// <param name="msg"></param>
        public virtual void Fail(Socket client, string msg)
        {
            this.Response(client, new RequestResult() { Code = "1", Message = msg });
        }
        public virtual void Fail(Socket client, string msg, string result)
        {
            this.Response(client, new RequestResult() { Code = "1", Message = msg, Result = result });
        }
        public virtual void Fail(Socket client, RequestResult response)
        {
            this.Response(client, response);
        }
        /// <summary>
        /// 成功
        /// </summary>
        /// <param name="client"></param>
        /// <param name="msg"></param>
        public virtual void Success(Socket client, string msg)
        {
            this.Response(client, new RequestResult() { Code = "0", Message = msg });
        }
        public virtual void Success(Socket client, string msg, string result)
        {
            this.Response(client, new RequestResult() { Code = "0", Message = msg, Result = result });
        }
        /// <summary>
        /// 发送、响应内容
        /// </summary>
        /// <param name="client"></param>
        /// <param name="response"></param>
        public virtual void Response(Socket client, RequestResult response)
        {
            XmlDocument doc = new XmlDocument();
            doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", "yes"));
            XmlElement root = doc.CreateElement("root");
            foreach (var item in response.GetFieldValue())
            {
                XmlElement node = doc.CreateElement(item.Key);
                node.InnerText = item.Value;
                root.AppendChild(node);
            }
            doc.AppendChild(root);
            this.Response(client, doc.OuterXml);
        }
        /// <summary>
        /// 发送、响应内容
        /// </summary>
        /// <param name="client"></param>
        /// <param name="response"></param>
        public virtual void Serializer(Socket client, RequestResult response)
        {
            byte[] bytes = new byte[0];
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                XmlSerializer xmlserializer = new XmlSerializer(typeof(RequestResult));
                xmlserializer.Serialize(stream, response);
                bytes = stream.ToArray();
            }
            this.Response(client, bytes);
        }
        /// <summary>
        /// 将客户发送响应信息
        /// </summary>
        /// <param name="client"></param>
        /// <param name="content"></param>
        public virtual void Response(Socket client, string content)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(content);
            this.Response(client, bytes);
        }
        /// <summary>
        /// 将客户发送响应信息
        /// </summary>
        /// <param name="client"></param>
        /// <param name="content"></param>
        public virtual void Response(Socket client, byte[] bytes)
        {
            try
            {
                client.Send(bytes);
            }
            catch (Exception ex)
            {
                Logger.Error("发送内容异常", ex);
            }
        }
        #endregion
        /// <summary>
        /// 停止、关闭服务器
        /// </summary>
        public void Stop()
        {
            try
            {
                if (this._socket != null)
                    this._socket.Disconnect(false);
                this._socket = null;
                Logger.Info("停止、关闭服务器");
            }
            catch (Exception ex)
            {
                Logger.Error("停止、关闭服务器异常：", ex);
            }
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            this.Stop();
        }
    }
}
